package msgpack

import (
	"encoding/json"
	"errors"
)

type Encoder interface {
	Encode(any) ([]byte, error)
}

type Decoder interface {
	DecodeTo(target any) error
	Data() string
}

//

type req struct {
	Name  string          `json:",omitempty"`
	DataB json.RawMessage `json:"Data,omitempty"`
}

func NewReq(name string) Encoder {
	return &req{Name: name}
}

func ParseReq(data []byte) (string, Decoder, error) {
	r := &req{}
	if err := json.Unmarshal(data, &r); err != nil {
		return "", nil, err
	}
	return r.Name, r, nil
}

func (r *req) Encode(data any) ([]byte, error) {
	b, err := json.Marshal(data)
	if err != nil {
		return nil, err
	}
	r.DataB = b
	return json.Marshal(r)
}

func (r *req) DecodeTo(target any) error {
	return json.Unmarshal(r.DataB, &target)
}

func (r *req) Data() string {
	return string(r.DataB)
}

//

type resp struct {
	DataB json.RawMessage `json:"Data,omitempty"`
	Err   string          `json:",omitempty"`
}

func NewResp() Encoder {
	return &resp{}
}

func ParseResp(data []byte) (Decoder, error) {
	r := &resp{}
	if err := json.Unmarshal(data, &r); err != nil {
		return nil, err
	}
	return r, nil
}

func (r *resp) Encode(data any) ([]byte, error) {
	if e, ok := data.(error); ok {
		r.Err = e.Error()
	} else {
		if b, err := json.Marshal(data); err != nil {
			r.Err = err.Error()
		} else {
			r.DataB = b
		}
	}
	return json.Marshal(r)
}

func (r *resp) DecodeTo(target any) error {
	if r.Err != "" {
		return errors.New(r.Err)
	}
	return json.Unmarshal(r.DataB, &target)
}

func (r *resp) Data() string {
	return string(r.DataB)
}
